#ifndef _BLOQUE_H_
#define _BLOQUE_H_

#include <cstdlib>
#include "tipo_struct.h"
#include "paresDatos.h"
#include "tipo_colec.h"
#include <list>

/********************************************************************
 * Bloque.h
 * 
 * Descripcion :Esta clase representa un bloque de datos. El bloque
 * contiene una cadena de bytes, con la serializacion de los registros
 * cargados en el mismo. 
*********************************************************************/

class Bloque {
	
	//atribs
	private:
	
		unsigned int num_bloque; //Numero del bloque
		unsigned int size; //tamanio del bloque
		unsigned int libre; //tamanio libre en el bloque
		char* datos; //Vector de bytes que representa los datos contenidos en le reg
		
		//Defino el constructor de copia privado para que no se pueda copiar el bloque
		Bloque(const Bloque& b);
		
	public:
		
		/* 
		 * Constructor: Construye un bloque con el tamanio y el numero de blque pasados por parametro.
		 * Inicializa el bloque con 0.
		 */
		Bloque(unsigned int num_bloque,unsigned int size);
		
		//Destructor: Libera la memoria consumida por el bloque.
		~Bloque();
		
		/*
		 * Append: Dado un registro pasado por param, lo serializa y lo
		 * mete en el bloque. Devuelve el tamanio del dato metido,
		 * si no pudo meter devuelve 0.
		 */
		unsigned int append (TipoStruct* dato);
		
		/*
		 * agrega al final del bloque, si es que entra, la cadena pasada por param
		 * siendo tam el tamanio de la cadena a escribir, SINO  no hace nada 
		 */
		void append (char* data, unsigned int tam);
		
		/*
		 * Get Registro: Dado un registro pasado por param, y una posicion
		 * en el bloque, desearializa la info del bloque y la mete en el registro.
		 * Devuelve false si no pudo obtenerlo.
		 */
		bool get_registro (TipoStruct* dato, unsigned int pos);
		
		/*
		 * Get Registros Desde: Dado un reg base, una posicion desde donde leer (por defecto 0),
		 * y un vector de registros, devuelve una copia de los registros del bloque llenando el vector.
		 * Los mismos deben ser liberados externamente. El reg base tmb debe ser liberado externamente.
		 */
		void get_registros_desde (TipoStruct* reg_base, std::vector<TipoStruct*> &registros, unsigned int pos = 0);
		
		/*
		 * Escribir: Escribe los bytes contenidos en el buffer pasado como param
		 * en el bloque. Se debe pasar la cantidad de bytes a escribir y la pos
		 * en donde escribir. Devuelve true si pudo escribir, false en caso contrario.
		 */
		bool escribir (const char* buf, unsigned int pos, unsigned int cant_bytes);
		
		/*
		 * Escribir Registro: Dado un registro pasado por param y una 
		 * posicion en el bloque lo dererializa y lo escribe a partir de la pos.
		 * Si no puede escribir devuelve false.
		 */ 
		bool escribir_registro(TipoStruct * dato, unsigned int pos);
		
		/*
		 * Leer: Devuelve en el buffer pasado como para una copia de los datos
		 * del bloque que empiezan en pos y tienen cant_bytes de longitud.
		 * Devuelve true si pudo leer, false en caso contrario.
		 */
		bool leer (char* buf,  unsigned int pos, unsigned int cant_bytes);
		
		/*
		 * Comprimir: Dada una pos y una cantidad de bytes, comprime el bloque esa
		 * cantidad desde pos eliminando los bytes contenidos en ese intervalo. 
		 * Actualiza el espacio libre del bloque.
		 * Devuelve true si lo puede comprimir, false en caso contrario.
		 */
		bool comprimir (unsigned int pos, unsigned int cant_bytes);
		
		/*
		 * Expandir: Dada una pos y una cantidad de bytes, expande el bloque esa
		 * cantidad desde pos, desplazando los bytes siguientes. 
		 * Actualiza el espacio libre del bloque.
		 * Devuelve true si lo puede expandir, false en caso contrario.
		 */
		bool expandir (unsigned int pos, unsigned int cant_bytes);
		
		/*
		 * Vaciar: Elimina la info dentro de bloque, dejando libre todo su espacio.
		 */
		void vaciar();
		
		/*
		 * Esta vacio: Devuelve true si el bloque esta vacio, false en caso contrario.
		 */
		bool esta_vacio();
		
		/*
		 * Setea el numero de bloque con el pasado por param.
		 */
		void set_num_bloque(unsigned int n_bloque);
		
		/*
		 * Get Num Bloque: Devuelve el numero de bloque.
		 */
		unsigned int get_num_bloque();
		
		/*
		 * Get Size: Devuelve el tamanio del bloque.
		 */
		unsigned int get_size();
		
		/*
		 * Get Espacio Libre: Devuelve el espacio libre en el bloque.
		 */
		unsigned int get_espacio_libre();
		
		/*
		 * Get Tope: devuelve la primer posicion libre. 
		 */
		 unsigned int get_tope(); 
		
		/*
		 * Busca un reg a partir de la pos pasada como param que cumpla con las condiciones
		 * exigidas en el vector de consultas. Si lo encuentra llena el registro con los datos,
		 * devuelve la pos donde lo encontro y el tamanio del reg en el bloque. Devuelve true.
		 * Si no lo encuentra o hay un error en la busqueda devuelve false.
		 */
		bool buscar_primero_desde(unsigned int pos, TipoStruct* reg, std::vector<ParesDatos*> &consultas, unsigned int &pos_res, unsigned int &size_res);
		
		
		/*
		 * Idem anterior pero busca siempre por el campo 0 del registro.
		 * Se debe pasar el dato en la pos 0.
		 */
		bool buscar_por_clave_desde(unsigned int pos, TipoDato* clave, TipoStruct* reg, unsigned int &pos_res, unsigned int &size_res);
		
		/*
		 * Consultar desde: Dada una pos, recorre todo el bloque de a pedazos
		 * intentado deserializar los bytes en un reg de la forma del pasado
		 * como param, y luego si cumple las condiciones lo coloca en el
		 * vector de resultados. Devuelve todos los regs en el bloque que cumplen
		 * con las consultas pasadas en el vector de pares de datos. 
		 * Si hay un error devuelve el vector de resultados vacio. */
		void consultar_desde(unsigned int pos, TipoStruct* reg_base, std::vector<ParesDatos*> &consultas, std::vector<TipoStruct*> &resultado);
		
		
		/*
		 * Quitar desde: Dada una pos, recorre todo el bloque de a pedazos
		 * intentado deserializar los bytes en un reg de la forma del pasado
		 * como param, y luego si cumple las condiciones lo elimina del bloque.
		 * Devuelve los registros que quito, y el tamanio que comprimio en el bloque.
		 */
		void quitar_desde(unsigned int pos, TipoStruct* reg_base, std::vector<ParesDatos*> &consultas, std::vector<TipoStruct*> &quitados, unsigned int &tam_quitado);
		
		/*
		 * Devuelve una copia del contenido del bloque tal cual esta.
		 * Debe ser liberada externamente.
		 */
		char* get_contenido();
		
		/*
		 * Copia los bytes procedentes del buf pasado como param al bloque.
		 * Actualiza el esp libre del bloque.
		 */
		void set_contenido(char* buf, unsigned int tam_buf);
		
		/*
		 * me devuelve el espacio que esta ocupado dentro del bloque 
		 */
		unsigned int get_esp_ocupado();
	
	private:
		
		/*
		 * Dado un registro y un vector de consultas devuelve true si el
		 * registro cumple con las consultas o false en caso contrario.
		 */
		bool cumple_condiciones(TipoStruct &reg, std::vector<ParesDatos*> &consultas);
		
		/*
		 * Coloca el espacio libre actual en el bloque.
		 */
		void set_esp_libre_en_bloque (unsigned int esp);
		
		/*
		 * Devuelve el espacio libre almacenado en el bloque.
		 */
		unsigned int get_esp_libre_en_bloque ();
		
		/*
		 * Devuelve el tamanio serializado de un registro.
		 */
		unsigned int get_tamanio_serializado(TipoStruct* reg);
		
};

#endif //FIN ARCHIVO BLOQUES
